#include "shape.h"
#include "shape_manager.h"

namespace vgl{
//a shape is a vector graph with several control points
//each control point has a control type, which determines 
//how can to control the shape



Shape::Shape(shape_type_t t){

	m_type = t;
	m_transform.Reset();
}

Shape::~Shape(){

	m_ctrl_pts.clear();
	//delete_vector(m_ctrl_pts);
}

void Shape::draw(graphics_t & g){

	draw_control_points(g);	
}

void Shape::get_bbox(rect_t & rc){

	rc.X = 0;
	rc.Y = 0;
	rc.Width = 0;
	rc.Height = 0;

	
	int xmin,ymin,xmax,ymax;


	std::vector<point_t>::iterator it = m_ctrl_pts.begin();
	bool b_first = true;
	while(it != m_ctrl_pts.end()){
	
		if(b_first){
			xmin = xmax = it->X;
			ymin = ymax = it->Y;
			b_first = false;
		}else{
			xmin = min(xmin,it->X);
			ymin = min(ymin,it->Y);

			xmax = max(xmax,it->X);
			ymax = max(ymax,it->Y);
		}
		
		it++;
	}

	rc.X = xmin;
	rc.Y = ymin;
	rc.Width = xmax-xmin;
	rc.Height = ymax-ymin;
}


//hit test for polygon,n is the polygon vertex count,
//we assume the first n control point are vertexs for 
//this polygon;
bool Shape::hit_test(point_t &pt,int n){

	//this test alrorithm works for both cancave and convex polygon,
	//but not for  polygon hole
	bool hit = false;

	int sz = n;

	for(int i=0,j=sz-1;i<sz;j=i++){
		if(((m_ctrl_pts[i].Y > pt.Y) != (m_ctrl_pts[j].Y > pt.Y)) && 
			(pt.X < (m_ctrl_pts[j].X - m_ctrl_pts[i].X) *(pt.Y-m_ctrl_pts[i].Y) /(m_ctrl_pts[j].Y - m_ctrl_pts[i].Y) + m_ctrl_pts[i].X))
		{
			hit = !hit;
		}
	}

	return hit;
}


void Shape::draw_control_points(graphics_t & g){
	//here ,control points are alreay transformed

	stencil_t *stencil = ShapeManager::get_stencil(shape_rectangle);
	std::vector<point_t>::iterator it = m_ctrl_pts.begin();
	std::vector<ctrl_point_t*>::iterator it_s = stencil->ctrl_pts.begin();

	assert(stencil->ctrl_pts.size() == m_ctrl_pts.size());

	
	while(it != m_ctrl_pts.end()){

		switch((*it_s)->ctl_type){
			case ctrl_resize:
				{	
					pen_t pen(color_t(255,0,0,0),1);
					SolidBrush br(color_t(255,255,0,0));
					
					g.FillEllipse(&br,rect_f_t(it->X-GRABBER_SIZE/2,it->Y-GRABBER_SIZE/2,GRABBER_SIZE,GRABBER_SIZE));
					g.DrawEllipse(&pen,rect_f_t(it->X-GRABBER_SIZE/2,it->Y-GRABBER_SIZE/2,GRABBER_SIZE,GRABBER_SIZE));
				}
				break;
			case ctrl_distort:
				{
					SolidBrush br(color_t(255,255,0,0));
					g.FillEllipse(&br,rect_f_t(it->X-GRABBER_SIZE/2,it->Y-GRABBER_SIZE/2,GRABBER_SIZE,GRABBER_SIZE));
				}
				break;
			case ctrl_rotate:
				{
					SolidBrush br(color_t(255,0,255,0));
					g.FillEllipse(&br,rect_f_t(it->X-GRABBER_SIZE/2,it->Y-GRABBER_SIZE/2,GRABBER_SIZE,GRABBER_SIZE));
				}
				break;
		}

		it++;
		it_s++;
	}
};



//
int Shape::hit_ctrl(point_t &pt){

	int idx = 0;
	rect_t rc;

	get_bbox(rc);
	rc.X -= GRABBER_SIZE/2;
	rc.Y -= GRABBER_SIZE/2;

	rc.Width += GRABBER_SIZE;
	rc.Height += GRABBER_SIZE;


	Gdiplus::Point pt2;
	pt2.X = pt.X;
	pt2.Y = pt.Y;
	
	if(rc.Contains(pt2)){
		for(unsigned i=0; i< m_ctrl_pts.size();i++){
			//construct the ctrl rectangle
			rect_t rc_ctrl;

			rc_ctrl.X  = m_ctrl_pts[i].X - GRABBER_SIZE/2;
			rc_ctrl.Y  = m_ctrl_pts[i].Y - GRABBER_SIZE/2;

			rc_ctrl.Width = GRABBER_SIZE;
			rc_ctrl.Height = GRABBER_SIZE;

			if(rc_ctrl.Contains(pt2)){
				idx = i+1;
				break;
			}

		}
	}else
		idx = 0;

	return idx;
}


};